﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CSP.Core
{
    public abstract class EntityPage : Page
    {
        protected abstract EntityDataSource EntitySource { get; }
        protected abstract GridView EntityGrid { get; }
        protected abstract DetailsView EntityDetails { get; }
        protected abstract TextBox EntitySearchTxt { get; }
        protected abstract Button EntityAddBtn { get; }
        protected abstract Button EntityClearBtn { get; }

        protected abstract void OnEntityDisabling(int entityKey);
        protected abstract void OnEntityInserting(EntityDataSourceChangingEventArgs e);
        protected abstract void OnEntityUpdating(EntityDataSourceChangingEventArgs e);
        protected abstract string GetEntitySortExpression(string keyword);

        private DetailsViewMode EntityMode { get; set; }
        private int EntityIndex { get; set; }

        private static readonly string[] SortDirections = new string[] { "asc", "desc" };

        protected object EvalX(string expression)
        {
            CheckPageExists();

            var ctd = base.Page.GetDataItem() as ICustomTypeDescriptor;
            if (ctd != null)
            {
                return DataBinder.Eval(ctd.GetPropertyOwner(null), expression);
            }
            else
                return null;
        }


        private void CheckPageExists()
        {
            if (base.Page == null)
            {
                throw new InvalidOperationException("TemplateControl_DataBindingRequiresPage");
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            EntitySource.Inserting += EntitySource_Inserting;
            EntitySource.Updating += EntitySource_Updating;
            EntitySource.Inserted += Entity_Changed;
            EntitySource.Updated += Entity_Changed;
            EntityAddBtn.Click += BtnAdd_Click;
            EntityClearBtn.Click += BtnClear_Click;
            EntityGrid.RowCommand += EntityGrid_RowCommand;
        }


        protected override void OnLoadComplete(EventArgs e)
        {
            base.OnLoadComplete(e);

            BindWhereClause();
            BindOrderByClause();
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            EntityDetails.Visible = EntityMode != DetailsViewMode.ReadOnly;

            if (EntityDetails.Visible && EntityDetails.CurrentMode != EntityMode)
                EntityDetails.ChangeMode(EntityMode);


            if (EntityDetails.Visible && EntityMode == DetailsViewMode.Edit)
            {
                EntityDetails.PageIndex = EntityIndex;
                EntityDetails.DataBind();
            }

            EntityAddBtn.Visible = !EntityDetails.Visible;
        }

        private void BtnAdd_Click(object sender, EventArgs e)
        {
            EntityMode = DetailsViewMode.Insert;
        }

        private void EntityGrid_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "Modify")
            {
                EntityIndex = int.Parse(e.CommandArgument as string) +
                    EntityGrid.PageIndex * EntityGrid.PageSize;
                EntityGrid.SelectedIndex = int.Parse(e.CommandArgument as string);

                EntityMode = DetailsViewMode.Edit;
            }
            else if (e.CommandName == "Disable")
            {
                var selectedIndex = int.Parse(e.CommandArgument as string);
                var entityKey = (int)EntityGrid.DataKeys[selectedIndex].Value;

                OnEntityDisabling(entityKey);

                Entity_Changed(null, null);
            }
        }

        private void BtnClear_Click(object sender, EventArgs e)
        {
            EntitySearchTxt.Text = null;
            Entity_Changed(null, null);
        }

        private void BindWhereClause()
        {
            if (!String.IsNullOrEmpty(EntitySearchTxt.Text))
            {
                if (!String.IsNullOrEmpty(EntitySource.Where))
                    EntitySource.Where += " and ";
                EntitySource.Where += GetEntitySortExpression(EntitySearchTxt.Text);
            }
        }

        private void EntitySource_Updating(object sender, EntityDataSourceChangingEventArgs e)
        {
            OnEntityUpdating(e);
        }

        private void EntitySource_Inserting(object sender, EntityDataSourceChangingEventArgs e)
        {
            OnEntityInserting(e);
        }

        private void BindOrderByClause()
        {
            if (!String.IsNullOrEmpty(EntityGrid.SortExpression))
                EntitySource.OrderBy = "it." + EntityGrid.SortExpression + " "
                    + SortDirections[(int)EntityGrid.SortDirection];
        }

        protected void Entity_Changed(object sender, EntityDataSourceChangedEventArgs e)
        {
            BindWhereClause();
            BindOrderByClause();
            EntityGrid.DataBind();
        }
    }
}
